#include "Measure2D.h"
#include <sstream>

unsigned char Measure2D::_mouseModeMeasure = SceneCenter::inst()->generateNewMouseMode();

Measure2D::Measure2D(void) : 
	LayerPlugin(LAYER_2D_SCENE)
{
	_lastDistance = 0;
	memset(&_lastPosition, 0, sizeof(_lastPosition));
	memset(&_currPosition, 0, sizeof(_currPosition));
}

Measure2D::~Measure2D(void)
{
}

bool Measure2D::initPlugin()
{
	EventCenter::inst()->registerHandler(this, MOUSE_CLICK_GROUP | MOUSE_MOTION_GROUP | KEYBOARD_GROUP, getParentViewer()->getStationId());

	_measureGroup = new Group;
	_lines = new Geometry;
	_labels = new Group;

	Geode* geode = new Geode;
	geode->addDrawable(_lines);

	_measureGroup->addChild(geode);
	_measureGroup->addChild(_labels);

	_linePoints = new Vec3Array;
	_lines->setVertexArray(_linePoints);

	Vec4Array* color = new Vec4Array;
	color->push_back(Vec4(0.5, 0.5, 1.0, 1.0));
	_lines->setColorArray(color);
	_lines->setColorBinding(Geometry::BIND_OVERALL);

	Vec3Array* normal = new Vec3Array;
	normal->push_back(Vec3(0, 0, 1));
	_lines->setNormalArray(normal);
	_lines->setNormalBinding(Geometry::BIND_OVERALL);

	_lineStrip = new DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, 0);	
	_lines->addPrimitiveSet(_lineStrip);

	return true;
}

void Measure2D::handleSystemEvent( unsigned eventType, int param1, int param2 )
{
	short mouseScrX, mouseScrY;

	switch (eventType)
	{
	case KEY_UP:
		if ((char)param1 == 'M' || (char)param1 == 'm')
		{
			if (SceneCenter::inst()->getMouseMode() == MOUSE_MODE_ROAM)
			{
				SceneCenter::inst()->setMouseMode(_mouseModeMeasure);
				_currStatus = MEASURE_ENABLE;
				getParentViewer()->getLayerManager()->addToNewLayer(_measureGroup, "Measure2D");
			}
			else if (SceneCenter::inst()->getMouseMode() == _mouseModeMeasure)
			{
				clearScreen();
				SceneCenter::inst()->setMouseMode(MOUSE_MODE_ROAM);
				getParentViewer()->getLayerManager()->removeLayer("Measure2D");
			}
			return;
		}

	case LBUTTON_DOWN:
		if (SceneCenter::inst()->getMouseMode() != _mouseModeMeasure)
		{
			return;
		}
		getFromParam(param1, mouseScrX, mouseScrY);
		onLButtonDown(mouseScrX, mouseScrY);
		break;

	case RBUTTON_DOWN:
		if (SceneCenter::inst()->getMouseMode() != _mouseModeMeasure)
		{
			return;
		}
		onRButtonDown();
		break;

	case MOUSE_MOVE:
		if (SceneCenter::inst()->getMouseMode() != _mouseModeMeasure)
		{
			return;
		}
		getFromParam(param1, mouseScrX, mouseScrY);
		onMouseMove(mouseScrX, mouseScrY);
		break;

	default:
		break;
	}
}

void Measure2D::onLButtonDown( short mouseScrX, short mouseScrY )
{
	Vec3 world;
	Camera2D* camera = dynamic_cast<Camera2D*>(getParentViewer()->getMainCamera());
	camera->screenToWorld(mouseScrX, mouseScrY, world);
	SceneCenter::inst()->XYToLL(world.x(), world.y(), _currPosition.lon, _currPosition.lat);

	if (_currStatus == MEASURE_END)
	{
		clearScreen();
	}


	if (_currStatus == MEASURE_ENABLE || _currStatus == MEASURE_END)
	{
		_lastDistance = 0;
		_lastPosition.lon = 0;
		_lastPosition.lat = 0;
		_linePoints->push_back(world);

		_lastPosition = _currPosition;
	}
	else if (_currStatus == MEASURE_MOVE || _currStatus == MEASURE_POINT)
	{
		double dist = calcDistance(_currPosition, _lastPosition);	
		_lastDistance += dist;
		_linePoints->push_back(world);
		_lineStrip->setCount(_linePoints->size());
		_lines->dirtyDisplayList();
		_lines->dirtyBound();

		ostringstream str;
		str << _lastDistance;
		Label* label = new Label(str.str(), 24, world.x(), world.y(), 0, 1, 0, 0, TextBase::CENTER_BOTTOM);		
		_labels->addChild(label);

		_lastPosition = _currPosition;
	}


	_currStatus = MEASURE_POINT;
}

void Measure2D::onRButtonDown()
{
	if (_currStatus == MEASURE_ENABLE || _currStatus == MEASURE_END)
	{
		SceneCenter::inst()->setMouseMode(MOUSE_MODE_ROAM);
		clearScreen();
		getParentViewer()->getLayerManager()->removeLayer("Measure2D");
	}
	else if (_currStatus == MEASURE_POINT)
	{
		_currStatus = MEASURE_END;
	}
	else if (_currStatus == MEASURE_MOVE)
	{
		_linePoints->pop_back();
		_lineStrip->setCount(_linePoints->size());
		_lines->dirtyBound();
		_lines->dirtyDisplayList();
		_currStatus = MEASURE_END;
	}
}

void Measure2D::onMouseMove(short mouseScrX, short mouseScrY)
{
	if (_currStatus == MEASURE_ENABLE || _currStatus == MEASURE_END) { return; }

	Vec3 world;
	Camera2D* camera = dynamic_cast<Camera2D*>(getParentViewer()->getMainCamera());
	camera->screenToWorld(mouseScrX, mouseScrY, world);
	SceneCenter::inst()->XYToLL(world.x(), world.y(), _currPosition.lon, _currPosition.lat);

	if (_currStatus == MEASURE_MOVE)
	{
		_linePoints->pop_back();
	}
	_linePoints->push_back(world);
	_lineStrip->setCount(_linePoints->size());
	_lines->dirtyDisplayList();
	_lines->dirtyBound();

	_currStatus = MEASURE_MOVE;
}

double Measure2D::calcDistance( const Position& pos1, const Position& pos2 )
{
	double lon1 = osg::DegreesToRadians(pos1.lon);
	double lat1 = osg::DegreesToRadians(pos1.lat);
	double lon2 = osg::DegreesToRadians(pos2.lon);
	double lat2 = osg::DegreesToRadians(pos2.lat);

	double dist = 0;
	dist = EARTH_R * acos(sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(lon1-lon2));

	return dist;
}

void Measure2D::clearScreen()
{
	_linePoints->clear();
	_lineStrip->setCount(0);
	_lines->dirtyBound();
	_lines->dirtyDisplayList();
	_labels->removeChildren(0, _labels->getNumChildren());
}
